package com.eshop.modules.product.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.eshop.api.EshopException;
import com.eshop.common.service.impl.BaseServiceImpl;
import com.eshop.common.utils.QueryHelpPlus;
import com.eshop.domain.BaseDomain;
import com.eshop.dozer.service.IGenerator;
import com.eshop.enums.*;
import com.eshop.exception.BadRequestException;
import com.eshop.exception.ErrorRequestException;
import com.eshop.modules.category.domain.StoreCategory;
import com.eshop.modules.category.service.StoreCategoryService;
import com.eshop.modules.product.domain.StoreProduct;
import com.eshop.modules.product.domain.StoreProductAttrValue;
import com.eshop.modules.product.domain.StoreProductRelation;
import com.eshop.modules.product.param.StoreProductQueryParam;
import com.eshop.modules.product.service.*;
import com.eshop.modules.product.service.dto.*;
import com.eshop.modules.product.service.mapper.StoreProductMapper;
import com.eshop.modules.product.vo.ProductVo;
import com.eshop.modules.product.vo.StoreProductAttrQueryVo;
import com.eshop.modules.product.vo.StoreProductQueryVo;
import com.eshop.modules.product.vo.StoreProductReplyQueryVo;
import com.eshop.modules.shop.service.SystemStoreService;
import com.eshop.modules.template.domain.ShippingTemplates;
import com.eshop.modules.template.service.ShippingTemplatesService;
import com.eshop.modules.user.service.UserService;
import com.eshop.utils.FileUtil;
import com.eshop.utils.RedisUtil;
import com.eshop.utils.RegexUtil;
import com.eshop.utils.ShopKeyUtils;
import com.github.pagehelper.PageInfo;
import com.qiniu.util.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = { Exception.class })
public class StoreProductServiceImpl extends BaseServiceImpl<StoreProductMapper, StoreProduct> implements StoreProductService
{
    @Autowired
    private IGenerator generator;
    @Autowired
    private StoreProductMapper storeProductMapper;
    @Autowired
    private StoreCategoryService storeCategoryService;
    @Autowired
    private StoreProductAttrService storeProductAttrService;
    @Autowired
    private StoreProductAttrValueService storeProductAttrValueService;
    @Autowired
    private UserService userService;
    @Autowired
    private StoreProductReplyService replyService;
    @Autowired
    private StoreProductRelationService relationService;
    @Autowired
    private SystemStoreService systemStoreService;
    @Autowired
    private ShippingTemplatesService shippingTemplatesService;
    
    public void incProductStock(final Integer num, final Long productId, final String unique, final Long activityId, final String type) {
        if (StrUtil.isNotEmpty((CharSequence)unique)) {
            this.storeProductAttrService.incProductAttrStock(num, productId, unique, type);
        }
        this.storeProductMapper.incStockDecSales(num, productId);
        if (ProductTypeEnum.COMBINATION.getValue().equals(type)) {
            this.storeProductMapper.incCombinationStockIncSales(num, productId, activityId);
        }
        else if (ProductTypeEnum.SECKILL.getValue().equals(type)) {
            this.storeProductMapper.incSeckillStockIncSales(num, productId, activityId);
        }
    }
    
    public void decProductStock(final int num, final Long productId, final String unique, final Long activityId, final String type) {
        if (StrUtil.isNotEmpty((CharSequence)unique)) {
            this.storeProductAttrService.decProductAttrStock(num, productId, unique, type);
        }
        final int product = this.storeProductMapper.decStockIncSales(num, productId);
        if (product == 0) {
            throw new EshopException("共享商品库存不足");
        }
        if (ProductTypeEnum.COMBINATION.getValue().equals(type)) {
            final int combinationRes = this.storeProductMapper.decCombinationStockIncSales(num, productId, activityId);
            if (combinationRes == 0) {
                throw new EshopException("拼团商品库存不足");
            }
        }
        else if (ProductTypeEnum.SECKILL.getValue().equals(type)) {
            final int seckillRes = this.storeProductMapper.decSeckillStockIncSales(num, productId, activityId);
            if (seckillRes == 0) {
                throw new EshopException("秒杀商品库存不足");
            }
        }
    }
    
    public StoreProduct getProductInfo(final Long id) {
        final LambdaQueryWrapper<StoreProduct> wrapper = (LambdaQueryWrapper<StoreProduct>)new LambdaQueryWrapper();
        (wrapper.eq(StoreProduct::getIsShow, 1)).eq(StoreProduct::getId, id);
        final StoreProduct storeProduct = (StoreProduct)((StoreProductMapper)this.baseMapper).selectOne((Wrapper)wrapper);
        if (ObjectUtil.isNull(storeProduct)) {
            throw new ErrorRequestException("商品不存在或已下架");
        }
        return storeProduct;
    }
    
    public StoreProductQueryVo getStoreProductById(final Long id) {
        return (StoreProductQueryVo)this.generator.convert(((StoreProductMapper)this.baseMapper).selectById((Serializable)id), (Class)StoreProductQueryVo.class);
    }
    
    public int getProductStock(final Long productId, final String unique, final String type) {
        //根据unique和productId去store_product_attr_value表查数据，这个表应该就是sku表
        final StoreProductAttrValue storeProductAttrValue = (StoreProductAttrValue)this.storeProductAttrValueService.getOne((Wrappers.<StoreProductAttrValue>lambdaQuery().eq(StoreProductAttrValue::getUnique, unique)).eq(StoreProductAttrValue::getProductId, productId));
        if (storeProductAttrValue == null) {
            return 0;
        }
        //判断是不是拼团或者秒杀商品，如果是拼团或者秒杀，就有专属库存
        if (ProductTypeEnum.PINK.getValue().equals(type)) {
            return storeProductAttrValue.getPinkStock();
        }
        if (ProductTypeEnum.SECKILL.getValue().equals(type)) {
            return storeProductAttrValue.getSeckillStock();
        }
        //普通商品的话就获取普通库存
        return storeProductAttrValue.getStock();
    }
    
    public List<StoreProductQueryVo> getGoodsList(final StoreProductQueryParam productQueryParam) {
        final LambdaQueryWrapper<StoreProduct> wrapper2 = (LambdaQueryWrapper<StoreProduct>)new LambdaQueryWrapper();
        wrapper2.eq(StoreProduct::getIsShow, CommonEnum.SHOW_STATUS_1.getValue());
        wrapper2.eq(BaseDomain::getIsDel, CommonEnum.DEL_STATUS_0.getValue());
        if (productQueryParam.getIsIntegral() != null) {
            wrapper2.eq(StoreProduct::getIsIntegral, productQueryParam.getIsIntegral());
        }
        if (StrUtil.isNotBlank((CharSequence)productQueryParam.getSid()) && !"0".equals(productQueryParam.getSid())) {
            wrapper2.eq(StoreProduct::getCateId, productQueryParam.getSid());
        }
        if (StrUtil.isNotEmpty((CharSequence)productQueryParam.getKeyword())) {
            wrapper2.and(wrapper1 -> {
                wrapper1.or();
                wrapper1.like(StoreProduct::getStoreName, productQueryParam.getKeyword());
                wrapper1.or();
                wrapper1.like(StoreProduct::getStoreInfo, productQueryParam.getKeyword());
                wrapper1.or();
                wrapper1.like(StoreProduct::getKeyword, productQueryParam.getKeyword());
                return;
            });
        }
        if (StrUtil.isNotBlank((CharSequence)productQueryParam.getNews()) && !"0".equals(productQueryParam.getNews())) {
            wrapper2.eq(StoreProduct::getIsNew, ShopCommonEnum.IS_NEW_1.getValue());
        }
        if (SortEnum.DESC.getValue().equals(productQueryParam.getSalesOrder())) {
            wrapper2.orderByDesc(StoreProduct::getSales);
        }
        else if (SortEnum.ASC.getValue().equals(productQueryParam.getSalesOrder())) {
            wrapper2.orderByAsc(StoreProduct::getSales);
        }
        if (SortEnum.DESC.getValue().equals(productQueryParam.getPriceOrder())) {
            wrapper2.orderByDesc(StoreProduct::getPrice);
        }
        else if (SortEnum.ASC.getValue().equals(productQueryParam.getPriceOrder())) {
            wrapper2.orderByAsc(StoreProduct::getPrice);
        }
        wrapper2.orderByDesc(StoreProduct::getSort);
        if (StringUtils.isNullOrEmpty(productQueryParam.getPriceOrder()) && StringUtils.isNullOrEmpty(productQueryParam.getSalesOrder())) {
            wrapper2.orderByDesc(StoreProduct::getId);
        }
        final Page<StoreProduct> pageModel = (Page<StoreProduct>)new Page((long)productQueryParam.getPage(), (long)productQueryParam.getLimit());
        final IPage<StoreProduct> pageList = this.storeProductMapper.selectPage((IPage<StoreProduct>)pageModel, (Wrapper<StoreProduct>)wrapper2);
        final List<StoreProductQueryVo> list = (List<StoreProductQueryVo>)this.generator.convert(pageList.getRecords(), (Class)StoreProductQueryVo.class);
        return list;
    }
    
    public Map<String, Object> getGoodsListByPage(final StoreProductQueryParam productQueryParam) {
        final LambdaQueryWrapper<StoreProduct> wrapper2 = (LambdaQueryWrapper<StoreProduct>)new LambdaQueryWrapper();
        wrapper2.eq(StoreProduct::getIsShow, CommonEnum.SHOW_STATUS_1.getValue());
        wrapper2.eq(BaseDomain::getIsDel, CommonEnum.DEL_STATUS_0.getValue());
        //如果查询积分商品这里不为空，就拼接一下积分条件
        if (productQueryParam.getIsIntegral() != null) {
            wrapper2.eq(StoreProduct::getIsIntegral, productQueryParam.getIsIntegral());
        }
        //分类ID不为空，且分类ID不为0，就拼接分类条件
        if (StrUtil.isNotBlank((CharSequence)productQueryParam.getSid()) && !"0".equals(productQueryParam.getSid())) {
            wrapper2.eq(StoreProduct::getCateId, productQueryParam.getSid());
        }
        //如果关键字不为空，那么就将店铺名，店铺描述，以及产品关键字拿去对比关键字条件
        if (StrUtil.isNotEmpty((CharSequence)productQueryParam.getKeyword())) {
            wrapper2.and(wrapper1 -> {
                wrapper1.or();
                wrapper1.like(StoreProduct::getStoreName, productQueryParam.getKeyword());
                wrapper1.or();
                wrapper1.like(StoreProduct::getStoreInfo, productQueryParam.getKeyword());
                wrapper1.or();
                wrapper1.like(StoreProduct::getKeyword, productQueryParam.getKeyword());
                return;
            });
        }
        //是否为新品
        if (StrUtil.isNotBlank((CharSequence)productQueryParam.getNews()) && !"0".equals(productQueryParam.getNews())) {
            wrapper2.eq(StoreProduct::getIsNew, ShopCommonEnum.IS_NEW_1.getValue());
        }
        //销量排序或者倒序
        if (SortEnum.DESC.getValue().equals(productQueryParam.getSalesOrder())) {
            wrapper2.orderByDesc(StoreProduct::getSales);
        }
        else if (SortEnum.ASC.getValue().equals(productQueryParam.getSalesOrder())) {
            wrapper2.orderByAsc(StoreProduct::getSales);
        }
        //价格排序或者倒序
        if (SortEnum.DESC.getValue().equals(productQueryParam.getPriceOrder())) {
            wrapper2.orderByDesc(StoreProduct::getPrice);
        }
        else if (SortEnum.ASC.getValue().equals(productQueryParam.getPriceOrder())) {
            wrapper2.orderByAsc(StoreProduct::getPrice);
        }
        //原生的商品sort排序
        wrapper2.orderByDesc(StoreProduct::getSort);
        //如果前端传来的价格和销量排序都为空，那么就根据StoreProduct的Id去排序
        if (StringUtils.isNullOrEmpty(productQueryParam.getPriceOrder()) && StringUtils.isNullOrEmpty(productQueryParam.getSalesOrder())) {
            wrapper2.orderByDesc(StoreProduct::getId);
        }
        //直接查出来就要的了
        final Page<StoreProduct> pageModel = (Page<StoreProduct>)new Page((long)productQueryParam.getPage(), (long)productQueryParam.getLimit());
        final IPage<StoreProduct> pageList = this.storeProductMapper.selectPage((IPage<StoreProduct>)pageModel, (Wrapper<StoreProduct>)wrapper2);
        final List<StoreProductQueryVo> list = (List<StoreProductQueryVo>)this.generator.convert(pageList.getRecords(), (Class)StoreProductQueryVo.class);
        final Map<String, Object> map = new LinkedHashMap<String, Object>(2);
        map.put("content", list);
        map.put("totalElements", pageList.getTotal());
        return map;
    }
    
    public ProductVo goodsDetail(final Long id, final Long uid, final String latitude, final String longitude) {
        final LambdaQueryWrapper<StoreProduct> wrapper = (LambdaQueryWrapper<StoreProduct>)new LambdaQueryWrapper();
        //is_show为1，且productId对应上的
        (wrapper.eq(StoreProduct::getIsShow, ShopCommonEnum.SHOW_1.getValue())).eq(StoreProduct::getId, id);
        //直接查出商品
        final StoreProduct storeProduct = (StoreProduct)this.storeProductMapper.selectOne((Wrapper)wrapper);
        if (ObjectUtil.isNull(storeProduct)) {
            throw new ErrorRequestException("商品不存在或已下架");
        }
        //获取sku详情
        final Map<String, Object> returnMap = this.storeProductAttrService.getProductAttrDetail(id);
        final ProductVo productVo = new ProductVo();
        //转换成vo对象
        final StoreProductQueryVo storeProductQueryVo = (StoreProductQueryVo)this.generator.convert(storeProduct, (Class)StoreProductQueryVo.class);
        //销量设置累加上虚拟销量
        storeProductQueryVo.setSales(storeProductQueryVo.getSales() + storeProductQueryVo.getFicti());
        //如果是一个已登录用户，计算vip价格以及判断是否收藏
        if (uid > 0L) {
            //根据用户等级计算出vip价格
            final double vipPrice = this.userService.setLevelPrice(storeProductQueryVo.getPrice().doubleValue(), uid);
            storeProductQueryVo.setVipPrice(BigDecimal.valueOf(vipPrice));
            //判断该商品是否已经收藏过了
            final boolean isCollect = this.relationService.isProductRelation(id, uid);
            storeProductQueryVo.setUserCollect(isCollect);
        }
        //查询出评论数量
        final int totalCount = this.replyService.productReplyCount(id);
        productVo.setReplyCount(totalCount);
        //获取一条评论
        final StoreProductReplyQueryVo storeProductReplyQueryVo = this.replyService.getReply(id);
        productVo.setReply(storeProductReplyQueryVo);
        //计算指定产品（由 productId 标识）获得的五星好评率（以百分比形式返回）
        final String replyPer = this.replyService.replyPer(id);
        productVo.setReplyChance(replyPer);
        //从Redis中获取出免去多少邮费
        final String storeFreePostage = (String)RedisUtil.get("store_free_postage");
        String tempName = "";
        //如果没有获取出值，或者值不是数字，或者值为0，都视为全国包邮
        if (StrUtil.isBlank((CharSequence)storeFreePostage) || !NumberUtil.isNumber((CharSequence)storeFreePostage) || Integer.valueOf(storeFreePostage) == 0) {
            tempName = "全国包邮";
        }
        else {
            //否则直接根据StoreProduct里的邮费模板ID去查询模板
            final ShippingTemplates shippingTemplates = (ShippingTemplates)this.shippingTemplatesService.getById((Serializable)storeProduct.getTempId());
            if (!ObjectUtil.isNotNull(shippingTemplates)) {
                //注意这里是BadRequestException
                throw new BadRequestException("请配置运费模板");
            }
            tempName = shippingTemplates.getName();
        }
        productVo.setTempName(tempName);
        productVo.setStoreInfo(storeProductQueryVo);
        productVo.setProductAttr((List<StoreProductAttrQueryVo>) returnMap.get("productAttr"));
        productVo.setProductValue((Map<String, StoreProductAttrValue>) returnMap.get("productValue"));
        //根据经纬度获取出自提店铺信息并设置进去
        productVo.setSystemStore(this.systemStoreService.getStoreInfo(latitude, longitude));
        //获取出腾讯云的mapKey
        productVo.setMapKey((String)RedisUtil.get(ShopKeyUtils.getTengXunMapKey()));
        //记录用户足迹，如果是登录用户
        if (uid > 0L) {
            //如果该用户不是第一次访问该商品，那就说明之前访问过了，因此直接修改CreatTime，修改数据库中的数据
            final StoreProductRelation foot = this.relationService.getOne(((Wrappers.<StoreProductRelation>lambdaQuery().eq(StoreProductRelation::getUid, uid)).eq(StoreProductRelation::getProductId, storeProductQueryVo.getId())).eq(StoreProductRelation::getType, "foot"));
            if (ObjectUtil.isNotNull(foot)) {
                foot.setCreateTime(new Date());
                //这里很细节，是saveOrUpdate，因为可能会被频繁调用，所以得用这个
                this.relationService.saveOrUpdate(foot);
            }
            //如果用户是第一次访问，就插入数据
            else {
                final StoreProductRelation storeProductRelation = new StoreProductRelation();
                storeProductRelation.setProductId(storeProductQueryVo.getId());
                storeProductRelation.setUid(uid);
                storeProductRelation.setCreateTime(new Date());
                storeProductRelation.setType("foot");
                this.relationService.save(storeProductRelation);
            }
        }
        return productVo;
    }
    
    public void incBrowseNum(final Long productId) {
        this.storeProductMapper.incBrowseNum(productId);
    }
    
    public List<StoreProductQueryVo> getList(final int page, final int limit, final int order) {
        final LambdaQueryWrapper<StoreProduct> wrapper = (LambdaQueryWrapper<StoreProduct>)new LambdaQueryWrapper();
        //展示，未逻辑删除，根据sort倒序
        ((wrapper.eq(StoreProduct::getIsShow, ShopCommonEnum.SHOW_1.getValue())).eq(BaseDomain::getIsDel, ShopCommonEnum.DELETE_0.getValue())).orderByDesc(StoreProduct::getSort);
        //不为积分商品
        wrapper.eq(StoreProduct::getIsIntegral, 0);
        //拼接看是哪一类商品
        switch (ProductEnum.toType(order)) {
            case TYPE_1: {
                wrapper.eq(StoreProduct::getIsBest, ShopCommonEnum.IS_STATUS_1.getValue());
                break;
            }
            case TYPE_3: {
                wrapper.eq(StoreProduct::getIsNew, ShopCommonEnum.IS_STATUS_1.getValue());
                break;
            }
            case TYPE_4: {
                wrapper.eq(StoreProduct::getIsBenefit, ShopCommonEnum.IS_STATUS_1.getValue());
                break;
            }
            case TYPE_2: {
                wrapper.eq(StoreProduct::getIsHot, ShopCommonEnum.IS_STATUS_1.getValue());
                break;
            }
        }
        //构造分页然后分页查询
        final Page<StoreProduct> pageModel = (Page<StoreProduct>)new Page((long)page, (long)limit);
        final IPage<StoreProduct> pageList = this.storeProductMapper.selectPage((IPage<StoreProduct>)pageModel, (Wrapper<StoreProduct>)wrapper);
        //转成vo对象
        return (List<StoreProductQueryVo>)this.generator.convert(pageList.getRecords(), (Class)StoreProductQueryVo.class);
    }
    
    public Map<String, Object> queryAll(final StoreProductQueryCriteria criteria, final Pageable pageable) {
        this.getPage(pageable);
        final PageInfo<StoreProduct> page = (PageInfo<StoreProduct>)new PageInfo((List)this.queryAll(criteria));
        final Map<String, Object> map = new LinkedHashMap<String, Object>(2);
        map.put("content", this.generator.convert(page.getList(), (Class)YxStoreProductDto.class));
        map.put("totalElements", page.getTotal());
        return map;
    }
    
    public List<StoreProduct> queryAll(final StoreProductQueryCriteria criteria) {
        final List<StoreProduct> storeProductList = (List<StoreProduct>)((StoreProductMapper)this.baseMapper).selectList((Wrapper)QueryHelpPlus.getPredicate(StoreProduct.class, criteria));
        storeProductList.forEach(yxStoreProduct -> yxStoreProduct.setStoreCategory((StoreCategory)this.storeCategoryService.getById((Serializable)yxStoreProduct.getCateId())));
        return storeProductList;
    }
    
    public void download(final List<YxStoreProductDto> all, final HttpServletResponse response) throws IOException {
        final List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
        for (final YxStoreProductDto yxStoreProduct : all) {
            final Map<String, Object> map = new LinkedHashMap<String, Object>();
            map.put("商户Id(0为总后台管理员创建,不为0的时候是商户后台创建)", yxStoreProduct.getMerId());
            map.put("商品图片", yxStoreProduct.getImage());
            map.put("轮播图", yxStoreProduct.getSliderImage());
            map.put("商品名称", yxStoreProduct.getStoreName());
            map.put("商品简介", yxStoreProduct.getStoreInfo());
            map.put("关键字", yxStoreProduct.getKeyword());
            map.put("产品条码（一维码）", yxStoreProduct.getBarCode());
            map.put("分类id", yxStoreProduct.getCateId());
            map.put("商品价格", yxStoreProduct.getPrice());
            map.put("会员价格", yxStoreProduct.getVipPrice());
            map.put("市场价", yxStoreProduct.getOtPrice());
            map.put("邮费", yxStoreProduct.getPostage());
            map.put("单位名", yxStoreProduct.getUnitName());
            map.put("排序", yxStoreProduct.getSort());
            map.put("销量", yxStoreProduct.getSales());
            map.put("库存", yxStoreProduct.getStock());
            map.put("状态（0：未上架，1：上架）", yxStoreProduct.getIsShow());
            map.put("是否热卖", yxStoreProduct.getIsHot());
            map.put("是否优惠", yxStoreProduct.getIsBenefit());
            map.put("是否精品", yxStoreProduct.getIsBest());
            map.put("是否新品", yxStoreProduct.getIsNew());
            map.put("产品描述", yxStoreProduct.getDescription());
            map.put("添加时间", yxStoreProduct.getAddTime());
            map.put("是否包邮", yxStoreProduct.getIsPostage());
            map.put("是否删除", yxStoreProduct.getIsDel());
            map.put("商户是否代理 0不可代理1可代理", yxStoreProduct.getMerUse());
            map.put("获得积分", yxStoreProduct.getGiveIntegral());
            map.put("成本价", yxStoreProduct.getCost());
            map.put("秒杀状态 0 未开启 1已开启", yxStoreProduct.getIsSeckill());
            map.put("砍价状态 0未开启 1开启", yxStoreProduct.getIsBargain());
            map.put("是否优品推荐", yxStoreProduct.getIsGood());
            map.put("虚拟销量", yxStoreProduct.getFicti());
            map.put("浏览量", yxStoreProduct.getBrowse());
            map.put("产品二维码地址(用户小程序海报)", yxStoreProduct.getCodePath());
            map.put("淘宝京东1688类型", yxStoreProduct.getSoureLink());
            list.add(map);
        }
        FileUtil.downloadExcel((List)list, response);
    }
    
    public void onSale(final Long id, Integer status) {
        if (ShopCommonEnum.SHOW_1.getValue().equals(status)) {
            status = ShopCommonEnum.SHOW_0.getValue();
        }
        else {
            status = ShopCommonEnum.SHOW_1.getValue();
        }
        this.storeProductMapper.updateOnsale(status, id);
    }
    
    public void insertAndEditYxStoreProduct(final StoreProductDto storeProductDto) {
        storeProductDto.setDescription(RegexUtil.converProductDescription(storeProductDto.getDescription()));
        final ProductResultDto resultDTO = this.computedProduct(storeProductDto.getAttrs());
        final StoreProduct storeProduct = new StoreProduct();
        BeanUtil.copyProperties(storeProductDto, storeProduct, new String[] { "sliderImage" });
        if (storeProductDto.getSliderImage().isEmpty()) {
            throw new EshopException("请上传轮播图");
        }
        storeProduct.setPrice(BigDecimal.valueOf(resultDTO.getMinPrice()));
        storeProduct.setOtPrice(BigDecimal.valueOf(resultDTO.getMinOtPrice()));
        storeProduct.setCost(BigDecimal.valueOf(resultDTO.getMinCost()));
        storeProduct.setIntegral(resultDTO.getMinIntegral());
        storeProduct.setStock(resultDTO.getStock());
        storeProduct.setSliderImage(String.join(",", storeProductDto.getSliderImage()));
        if (storeProductDto.getId() != null) {
            this.deleteForwardImg(storeProductDto.getId());
        }
        this.saveOrUpdate(storeProduct);
        if (SpecTypeEnum.TYPE_0.getValue().equals(storeProductDto.getSpecType())) {
            final FromatDetailDto fromatDetailDto = FromatDetailDto.builder().value("规格").detailValue("").attrHidden("").detail(ListUtil.toList(new String[] { "默认" })).build();
            final List<ProductFormatDto> attrs = storeProductDto.getAttrs();
            final ProductFormatDto productFormatDto = attrs.get(0);
            productFormatDto.setValue1("规格");
            final Map<String, String> map = new HashMap<String, String>();
            map.put("规格", "默认");
            productFormatDto.setDetail(map);
            this.storeProductAttrService.insertYxStoreProductAttr(ListUtil.toList(new FromatDetailDto[] { fromatDetailDto }), ListUtil.toList(new ProductFormatDto[] { productFormatDto }), storeProduct.getId());
        }
        else {
            this.storeProductAttrService.insertYxStoreProductAttr(storeProductDto.getItems(), storeProductDto.getAttrs(), storeProduct.getId());
        }
    }
    
    public Map<String, Object> getFormatAttr(final Long id, final String jsonStr, final boolean isActivity) {
        final JSONObject jsonObject = JSON.parseObject(jsonStr);
        final Map<String, Object> resultMap = new LinkedHashMap<String, Object>(3);
        if (jsonObject == null || jsonObject.get("attrs") == null || jsonObject.getJSONArray("attrs").isEmpty()) {
            resultMap.put("attr", new ArrayList());
            resultMap.put("value", new ArrayList());
            resultMap.put("header", new ArrayList());
            return resultMap;
        }
        final List<FromatDetailDto> fromatDetailDTOList = (List<FromatDetailDto>)JSON.parseArray(jsonObject.get("attrs").toString(), (Class)FromatDetailDto.class);
        final DetailDto detailDto = this.attrFormat(fromatDetailDTOList);
        List<Map<String, Object>> headerMapList = null;
        final List<Map<String, Object>> valueMapList = new ArrayList<Map<String, Object>>();
        final String align = "center";
        final Map<String, Object> headerMap = new LinkedHashMap<String, Object>();
        for (final Map<String, Map<String, String>> map : detailDto.getRes()) {
            final Map<String, String> detail = map.get("detail");
            final String[] detailArr = detail.values().toArray(new String[0]);
            Arrays.sort(detailArr);
            final String sku = String.join(",", (CharSequence[])detailArr);
            final Map<String, Object> valueMap = new LinkedHashMap<String, Object>();
            final List<String> detailKeys = detail.entrySet().stream().map(Map.Entry::getKey).collect(Collectors.toList());
            int i = 0;
            headerMapList = new ArrayList<Map<String, Object>>();
            for (final String title : detailKeys) {
                headerMap.put("title", title);
                headerMap.put("minWidth", "130");
                headerMap.put("align", align);
                headerMap.put("key", "value" + (i + 1));
                headerMap.put("slot", "value" + (i + 1));
                headerMapList.add((Map<String, Object>)ObjectUtil.clone(headerMap));
                ++i;
            }
            final String[] detailValues = detail.values().toArray(new String[0]);
            for (int j = 0; j < detailValues.length; ++j) {
                final String key = "value" + (j + 1);
                valueMap.put(key, detailValues[j]);
            }
            valueMap.put("detail", detail);
            valueMap.put("sku", "");
            valueMap.put("pic", "");
            valueMap.put("price", 0);
            valueMap.put("cost", 0);
            valueMap.put("ot_price", 0);
            valueMap.put("stock", 0);
            valueMap.put("bar_code", "");
            valueMap.put("weight", 0);
            valueMap.put("volume", 0);
            valueMap.put("brokerage", 0);
            valueMap.put("brokerage_two", 0);
            valueMap.put("pink_price", 0);
            valueMap.put("seckill_price", 0);
            valueMap.put("pink_stock", 0);
            valueMap.put("seckill_stock", 0);
            valueMap.put("integral", 0);
            if (id > 0L) {
                final StoreProductAttrValue storeProductAttrValue = (StoreProductAttrValue)this.storeProductAttrValueService.getOne((Wrappers.<StoreProductAttrValue>lambdaQuery().eq(StoreProductAttrValue::getProductId, id)).eq(StoreProductAttrValue::getSku, sku));
                if (storeProductAttrValue != null) {
                    valueMap.put("sku", storeProductAttrValue.getSku());
                    valueMap.put("pic", storeProductAttrValue.getImage());
                    valueMap.put("price", storeProductAttrValue.getPrice());
                    valueMap.put("cost", storeProductAttrValue.getCost());
                    valueMap.put("ot_price", storeProductAttrValue.getOtPrice());
                    valueMap.put("stock", storeProductAttrValue.getStock());
                    valueMap.put("bar_code", storeProductAttrValue.getBarCode());
                    valueMap.put("weight", storeProductAttrValue.getWeight());
                    valueMap.put("volume", storeProductAttrValue.getVolume());
                    valueMap.put("brokerage", storeProductAttrValue.getBrokerage());
                    valueMap.put("brokerage_two", storeProductAttrValue.getBrokerageTwo());
                    valueMap.put("pink_price", storeProductAttrValue.getPinkPrice());
                    valueMap.put("seckill_price", storeProductAttrValue.getSeckillPrice());
                    valueMap.put("pink_stock", storeProductAttrValue.getPinkStock());
                    valueMap.put("seckill_stock", storeProductAttrValue.getSeckillStock());
                    valueMap.put("integral", storeProductAttrValue.getIntegral());
                }
            }
            valueMapList.add((Map<String, Object>)ObjectUtil.clone(valueMap));
        }
        this.addMap(headerMap, headerMapList, align, isActivity);
        resultMap.put("attr", fromatDetailDTOList);
        resultMap.put("value", valueMapList);
        resultMap.put("header", headerMapList);
        return resultMap;
    }
    
    private ProductResultDto computedProduct(final List<ProductFormatDto> attrs) {
        final Double minPrice = attrs.stream().map(ProductFormatDto::getPrice).min(Comparator.naturalOrder()).orElse(0.0);
        final Integer minIntegral = attrs.stream().map(ProductFormatDto::getIntegral).min(Comparator.naturalOrder()).orElse(0);
        final Double minOtPrice = attrs.stream().map(ProductFormatDto::getOtPrice).min(Comparator.naturalOrder()).orElse(0.0);
        final Double minCost = attrs.stream().map(ProductFormatDto::getCost).min(Comparator.naturalOrder()).orElse(0.0);
        final Integer stock = attrs.stream().map(ProductFormatDto::getStock).reduce(Integer::sum).orElse(0);
        if (stock <= 0) {
            throw new EshopException("库存不能低于0");
        }
        return ProductResultDto.builder().minPrice(minPrice).minOtPrice(minOtPrice).minCost(minCost).stock(stock).minIntegral(minIntegral).build();
    }
    
    private List<ProductFormatDto> ListMapToListBean(final List<Map<String, Object>> listMap) {
        final List<ProductFormatDto> list = new ArrayList<ProductFormatDto>();
        for (final Map<String, Object> m : listMap) {
            list.add((ProductFormatDto)BeanUtil.mapToBean((Map)m, (Class)ProductFormatDto.class, true));
        }
        return list;
    }
    
    private void addMap(final Map<String, Object> headerMap, final List<Map<String, Object>> headerMapList, final String align, final boolean isActivity) {
        headerMap.put("title", "图片");
        headerMap.put("slot", "pic");
        headerMap.put("align", align);
        headerMap.put("minWidth", 80);
        headerMapList.add((Map<String, Object>)ObjectUtil.clone(headerMap));
        headerMap.put("title", "售价");
        headerMap.put("slot", "price");
        headerMap.put("align", align);
        headerMap.put("minWidth", 120);
        headerMapList.add((Map<String, Object>)ObjectUtil.clone(headerMap));
        headerMap.put("title", "成本价");
        headerMap.put("slot", "cost");
        headerMap.put("align", align);
        headerMap.put("minWidth", 140);
        headerMapList.add((Map<String, Object>)ObjectUtil.clone(headerMap));
        headerMap.put("title", "原价");
        headerMap.put("slot", "ot_price");
        headerMap.put("align", align);
        headerMap.put("minWidth", 140);
        headerMapList.add((Map<String, Object>)ObjectUtil.clone(headerMap));
        headerMap.put("title", "库存");
        headerMap.put("slot", "stock");
        headerMap.put("align", align);
        headerMap.put("minWidth", 140);
        headerMapList.add((Map<String, Object>)ObjectUtil.clone(headerMap));
        headerMap.put("title", "产品编号");
        headerMap.put("slot", "bar_code");
        headerMap.put("align", align);
        headerMap.put("minWidth", 140);
        headerMapList.add((Map<String, Object>)ObjectUtil.clone(headerMap));
        headerMap.put("title", "重量(KG)");
        headerMap.put("slot", "weight");
        headerMap.put("align", align);
        headerMap.put("minWidth", 140);
        headerMapList.add((Map<String, Object>)ObjectUtil.clone(headerMap));
        headerMap.put("title", "体积(m³)");
        headerMap.put("slot", "volume");
        headerMap.put("align", align);
        headerMap.put("minWidth", 140);
        headerMapList.add((Map<String, Object>)ObjectUtil.clone(headerMap));
        headerMap.put("title", "所需兑换积分");
        headerMap.put("slot", "integral");
        headerMap.put("align", align);
        headerMap.put("minWidth", 140);
        headerMapList.add((Map<String, Object>)ObjectUtil.clone(headerMap));
        if (isActivity) {
            headerMap.put("title", "拼团价");
            headerMap.put("slot", "pink_price");
            headerMap.put("align", align);
            headerMap.put("minWidth", 140);
            headerMapList.add((Map<String, Object>)ObjectUtil.clone(headerMap));
            headerMap.put("title", "拼团活动库存");
            headerMap.put("slot", "pink_stock");
            headerMap.put("align", align);
            headerMap.put("minWidth", 140);
            headerMapList.add((Map<String, Object>)ObjectUtil.clone(headerMap));
            headerMap.put("title", "秒杀价");
            headerMap.put("slot", "seckill_price");
            headerMap.put("align", align);
            headerMap.put("minWidth", 140);
            headerMapList.add((Map<String, Object>)ObjectUtil.clone(headerMap));
            headerMap.put("title", "秒杀活动库存");
            headerMap.put("slot", "seckill_stock");
            headerMap.put("align", align);
            headerMap.put("minWidth", 140);
            headerMapList.add((Map<String, Object>)ObjectUtil.clone(headerMap));
        }
        headerMap.put("title", "操作");
        headerMap.put("slot", "action");
        headerMap.put("align", align);
        headerMap.put("minWidth", 70);
        headerMapList.add((Map<String, Object>)ObjectUtil.clone(headerMap));
    }
    
    private DetailDto attrFormat(final List<FromatDetailDto> fromatDetailDTOList) {
        List<String> data = new ArrayList<String>();
        final List<Map<String, Map<String, String>>> res = new ArrayList<Map<String, Map<String, String>>>();
        fromatDetailDTOList.stream().map(FromatDetailDto::getDetail).forEach(i -> {
            if (i == null || i.isEmpty()) {
                throw new EshopException("请至少添加一个规格值哦");
            }
            else {
                String str = ArrayUtil.join(i.toArray(), (CharSequence)",");
                if (str.contains("-")) {
                    throw new EshopException("规格值里包含'-',请重新添加");
                }
                else {
                    return;
                }
            }
        });
        if (fromatDetailDTOList.size() > 1) {
            for (int j = 0; j < fromatDetailDTOList.size() - 1; ++j) {
                if (j == 0) {
                    data = fromatDetailDTOList.get(j).getDetail();
                }
                final List<String> tmp = new LinkedList<String>();
                for (final String v : data) {
                    for (final String g : fromatDetailDTOList.get(j + 1).getDetail()) {
                        String rep2 = "";
                        if (j == 0) {
                            rep2 = fromatDetailDTOList.get(j).getValue() + "_" + v + "-" + fromatDetailDTOList.get(j + 1).getValue() + "_" + g;
                        }
                        else {
                            rep2 = v + "-" + fromatDetailDTOList.get(j + 1).getValue() + "_" + g;
                        }
                        tmp.add(rep2);
                        if (j == fromatDetailDTOList.size() - 2) {
                            final Map<String, Map<String, String>> rep3 = new LinkedHashMap<String, Map<String, String>>();
                            final Map<String, String> reptemp = new LinkedHashMap<String, String>();
                            for (final String h : Arrays.asList(rep2.split("-"))) {
                                final List<String> rep4 = Arrays.asList(h.split("_"));
                                if (rep4.size() > 1) {
                                    reptemp.put(rep4.get(0), rep4.get(1));
                                }
                                else {
                                    reptemp.put(rep4.get(0), "");
                                }
                            }
                            rep3.put("detail", reptemp);
                            res.add(rep3);
                        }
                    }
                }
                if (!tmp.isEmpty()) {
                    data = tmp;
                }
            }
        }
        else {
            final List<String> dataArr = new ArrayList<String>();
            for (final FromatDetailDto fromatDetailDTO : fromatDetailDTOList) {
                for (final String str2 : fromatDetailDTO.getDetail()) {
                    final Map<String, Map<String, String>> map2 = new LinkedHashMap<String, Map<String, String>>();
                    dataArr.add(fromatDetailDTO.getValue() + "_" + str2);
                    final Map<String, String> map3 = new LinkedHashMap<String, String>();
                    map3.put(fromatDetailDTO.getValue(), str2);
                    map2.put("detail", map3);
                    res.add(map2);
                }
            }
            final String s = StrUtil.join((CharSequence)"-", new Object[] { dataArr });
            data.add(s);
        }
        final DetailDto detailDto = new DetailDto();
        detailDto.setData(data);
        detailDto.setRes(res);
        return detailDto;
    }
    
    public void deleteForwardImg(final Long id) {
        ((StoreProductMapper)this.baseMapper).deleteForwardImg(id, "_product_detail_wap");
    }
}
